package controllers

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	"encoding/json"
	"net/http"
	"howie_api/utils"
	"strings"
	"errors"
)

type BaserControllers struct {
	beego.Controller
}

func (c *BaserControllers) GetUid() (uid int) {
	token := c.Ctx.Input.Header("Token")
	var err error
	if uid, err = utils.GetUidByToken(token); err != nil {
		c.RespFail(CODE_TOKEN_ERR, err.Error())
		return
	}
	return
}

func (c *BaserControllers) InputBaseData(d interface{}) (err error) {
	body := c.Ctx.Input.RequestBody
	if err = json.Unmarshal(body, d); err != nil {
		c.RespFail(CODE_INCORRECT_PARAMETER, "转化参数失败")
		c.StopRun()
	}
	return json.Unmarshal(body, d)
}

func (c *BaserControllers) RespSuccess() {
	c.resp(http.StatusOK, "OK")
}

func (c *BaserControllers) RespFail(code int, msg string) {
	c.resp(code, msg)
}

func (c *BaserControllers) RespData(data interface{}) {
	c.resp(http.StatusOK, data)
}


func (c *BaserControllers) RespDataWithPage(data interface{}, total int64) {
	c.resp(http.StatusOK, map[string]interface{}{
		"data":  data,
		"total": total,
	})
}

func (c *BaserControllers) resp(code int, data interface{}) {
	c.Ctx.Output.SetStatus(code)
	var hasIndent = true
	if beego.BConfig.RunMode == beego.PROD {
		hasIndent = false
	}
	c.Ctx.Output.JSON(data, hasIndent, false)
}
//
func (c *BaserControllers) GetAllAndTotal(models interface{}, contains interface{}) (err error, total int64) {
	var fields []string
	var sortby []string
	var order []string
	var query = make(map[string]string)
	var limit int64
	var offset int64

	// fields: col1,col2,entity.col3
	if v := c.GetString("fields"); v != "" {
		fields = strings.Split(v, ",")
	}
	// limit: 10 (default is 10)
	if v, err := c.GetInt64("limit"); err == nil {
		limit = v
	}
	// offset: 0 (default is 0)
	if v, err := c.GetInt64("offset"); err == nil {
		offset = v
	}
	// sortby: col1,col2
	if v := c.GetString("sortby"); v != "" {
		sortby = strings.Split(v, ",")
	}
	// order: desc,asc
	if v := c.GetString("order"); v != "" {
		order = strings.Split(v, ",")
	}
	// query: k:v,k:v
	if v := c.GetString("query"); v != "" {
		for _, cond := range strings.Split(v, ",") {
			kv := strings.SplitN(cond, ":", 2)
			if len(kv) != 2 {
				c.Data["json"] = errors.New("Error: invalid query key/value pair")
				c.ServeJSON()
				return
			}
			k, v := kv[0], kv[1]
			query[k] = v
		}
	}
	o := orm.NewOrm()
	qs := o.QueryTable(models)
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		if strings.Contains(k, "isnull") {
			qs = qs.Filter(k, (v == "true" || v == "1"))
		} else {
			qs = qs.Filter(k, v)
		}
	}
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					err = errors.New("Error: Invalid order. Must be either [asc|desc]")
					return
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					err = errors.New("Error: Invalid order. Must be either [asc|desc]")
					return
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
			return
		}
	} else {
		if len(order) != 0 {
			err = errors.New("Error: unused 'order' fields")
			return
		}
	}
	total, err = qs.Count()
	if err != nil {
		err = errors.New("获取总数失败")
		return
	}
	qs = qs.OrderBy(sortFields...)
	_, err = qs.Limit(limit, offset).All(contains, fields...)
	return
}
